/*
 * Copyright (C) 2012 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package com.gitee.l0km.thrift.swift2thrift.generator;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.gitee.l0km.xthrift.base.doc.CommentProviderFactories.providerOf;
import static com.gitee.l0km.xthrift.base.doc.CommentProviderFactories.withValidFactory;
import static com.gitee.l0km.xthrift.base.metadata.Decorators.javadocCommentProviderFactory;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.Nullable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.stringtemplate.v4.AutoIndentWriter;
import org.stringtemplate.v4.ST;
import com.facebook.swift.codec.ThriftField.Requiredness;
import com.facebook.swift.codec.ThriftProtocolType;
import com.facebook.swift.codec.metadata.FieldKind;
import com.facebook.swift.codec.metadata.ReflectionHelper;
import com.facebook.swift.codec.metadata.ThriftCatalog;
import com.facebook.swift.codec.metadata.ThriftFieldMetadata;
import com.facebook.swift.codec.metadata.ThriftStructMetadata;
import com.facebook.swift.codec.metadata.ThriftType;
import com.gitee.l0km.javadocreader.ClassCommentProviderFactoryImpl;
import com.gitee.l0km.xthrift.base.metadata.DecoratorThriftEnumMetadata;
import com.gitee.l0km.xthrift.base.metadata.DecoratorThriftEnumMetadata.ExtensiveEnumItem;
import com.gitee.l0km.xthrift.base.metadata.DecoratorThriftFieldMetadata;
import com.gitee.l0km.xthrift.base.metadata.DecoratorThriftStructMetadata;
import com.gitee.l0km.xthrift.base.metadata.ErpcNameTransformer;
import com.gitee.l0km.xthrift.base.metadata.ErpcProxyReturnCode;
import com.gitee.l0km.xthrift.base.metadata.ErpcType;
import com.gitee.l0km.xthrift.base.metadata.FieldNameFilters;
import com.gitee.l0km.xthrift.base.metadata.ThriftCatalogWithTransformer;
import com.gitee.l0km.xthrift.thrift.metadata.DecoratorThriftServiceMetadata;
import com.facebook.swift.generator.swift2thrift.Swift2ThriftGeneratorConfig;
import com.facebook.swift.generator.swift2thrift.template.FieldRequirednessRenderer;
import com.facebook.swift.generator.swift2thrift.template.ThriftContext;
import com.facebook.swift.generator.swift2thrift.template.ThriftServiceMetadataRenderer;
import com.facebook.swift.generator.swift2thrift.template.ThriftTypeRenderer;
import com.facebook.swift.service.ThriftService;
import com.facebook.swift.service.metadata.ThriftMethodMetadata;
import com.facebook.swift.service.metadata.ThriftServiceMetadata;
import com.gitee.l0km.com4j.base.ClassLoaderUtils;
import com.gitee.l0km.com4j.base.MiscellaneousUtils;
import com.gitee.l0km.javadocreader.JavadocReader;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.io.Files;
import com.google.common.reflect.TypeToken;

/**
 * 大部分代码复制自{@link com.facebook.swift.generator.swift2thrift.Swift2ThriftGenerator}(base version 0.23.1)<br>
 * 修改{@link #convertToThrift(Class)}方法，创建{@link ThriftServiceMetadata}替换为自定义{@link DecoratorThriftServiceMetadata}对象
 * @author guyadong
 *
 */
public class Swift2ThriftGenerator
{
    private static final Logger LOG = LoggerFactory.getLogger(Swift2ThriftGenerator.class);
    private final OutputStreamWriter outputStreamWriter;
    private final boolean verbose;
    /** 新增字段:使用定制的{@link ThriftCatalog}类型
	 * 重写{@link getThriftStructMetadata}方法，
	 * 将{@link ThriftStructMetadata}转换为{@link DecoratorThriftStructMetadata}
     */
    /*private final ThriftCatalog catalog = new ThriftCatalog() {
    	@Override
    	public <T> ThriftStructMetadata getThriftStructMetadata(Type structType) {
    		return DecoratorThriftStructMetadata.STRUCT_TRANSFORMER.apply(super.getThriftStructMetadata(structType));
    	}
    };*/
    
    private final ThriftCatalog catalog = ThriftCatalogWithTransformer.CATALOG;
    private final String defaultPackage;
    private final String allowMultiplePackages;     // null means don't allow
    private static final Map<String, String> defaultExcludeFields = ImmutableMap.of("gu.sql2java.BaseBean","modified,initialized");
	private ThriftTypeRenderer thriftTypeRenderer;
    private ArrayList<ThriftType> thriftTypes = Lists.newArrayList();
    private ArrayList<ThriftServiceMetadata> thriftServices = Lists.newArrayList();
    private String packageName;
    // includeMap maps a ThriftType or a ThriftServiceMetadata to the include that defines it
    private Map<Object, String> includeMap = Maps.newHashMap();
    private Set<ThriftType> usedIncludedTypes = Sets.newHashSet();
    private Set<ThriftServiceMetadata> usedIncludedServices = Sets.newHashSet();
    private Set<ThriftType> knownTypes = Sets.newHashSet(builtInKnownTypes);
    private Set<ThriftServiceMetadata> knownServices = Sets.newHashSet();
    private Map<String, String> namespaceMap;
    private boolean recursive;
	private String excludeMethods;
	private String includeMethods;
	private boolean sortByInclude = false;
	private boolean generateErpcIDL = false;
	private String programName;
	private String portPrefix;
	private int defaultMaxLength=256;
	private int errmsgMaxLength=256;
	private boolean erpcProxy = true;
	private ClassLoader parentClassLoader;
	private volatile ClassLoader classLoader;
	private static final Set<ThriftType> builtInKnownTypes =
        ImmutableSet.of(ThriftType.BOOL, ThriftType.BYTE, ThriftType.I16, ThriftType.I32,
            ThriftType.I64, ThriftType.DOUBLE, ThriftType.STRING, ThriftType.BINARY,
            new ThriftType(ThriftType.BOOL, Boolean.class), new ThriftType(ThriftType.BYTE, Byte.class),
            new ThriftType(ThriftType.I16, Short.class), new ThriftType(ThriftType.I32, Integer.class),
            new ThriftType(ThriftType.I64, Long.class), new ThriftType(ThriftType.DOUBLE, Double.class),
            new ThriftType(ThriftType.STRING, String.class), new ThriftType(ThriftType.STRING, byte[].class));
	public Swift2ThriftGenerator(final Swift2ThriftGeneratorConfig config) throws FileNotFoundException
    {
        this.verbose = config.isVerbose();
        String defaultPackage = config.getDefaultPackage();

        if (defaultPackage.isEmpty()) {
            this.defaultPackage = "";
        } else {
            this.defaultPackage = defaultPackage + ".";
        }

        OutputStream os = config.getOutputFile() != null ? new FileOutputStream(config.getOutputFile()) : System.out;
        this.outputStreamWriter = new OutputStreamWriter(os, Charsets.UTF_8);
        Map<String, String> paramIncludeMap = config.getIncludeMap();
        // create a type renderer with an empty map until we build it
        this.thriftTypeRenderer = new ThriftTypeRenderer(ImmutableMap.<ThriftType,String>of());
        for (Map.Entry<String, String> entry: paramIncludeMap.entrySet()) {
            Class<?> cls = load(entry.getKey());
            if (cls == null) {
                continue;
            }

            Object result = convertToThrift(cls);
            if (result != null) {
                this.includeMap.put(result, entry.getValue());
            }
        }

        this.namespaceMap = config.getNamespaceMap();
        this.allowMultiplePackages = config.isAllowMultiplePackages();
        this.recursive = config.isRecursive();
    }

    public void parse(Iterable<String> inputs) throws IOException
    {
        boolean loadErrors = false;

        if (allowMultiplePackages != null) {
            packageName = allowMultiplePackages;
        }

        for (String className: inputs) {
            Class<?> cls = load(className);
            if (cls == null) {
                loadErrors = true;
                continue;
            }

            if (packageName == null) {
                packageName = cls.getPackage().getName();
            } else if (!packageName.equals(cls.getPackage().getName())) {
                if (allowMultiplePackages == null) {
                    throw new IllegalStateException(
                        String.format("Class %s is in package %s, previous classes were in package %s",
                            cls.getName(), cls.getPackage().getName(), packageName));
                }
            }

            Object result = convertToThrift(cls);
            if (result instanceof ThriftType) {
                thriftTypes.add((ThriftType)result);
            } else if (result instanceof ThriftServiceMetadata) {
                thriftServices.add((ThriftServiceMetadata)result);
            }
            // if the class we just loaded was also in the include map, remove it from there
            includeMap.remove(result);
        }
        if (loadErrors) {
            LOG.error("Couldn't load some classes");
            return;
        }

        if (verify()) {
            gen();
        } else {
            LOG.error("Errors found during verification.");
        }
    }

    private String getFullClassName(String className)
    {
        if (className.indexOf('.') == -1) {
            return defaultPackage + className;
        } else {
            return className;
        }
    }

    private boolean verify()
    {
        if (recursive) {
            // Call verifyStruct and verifyService until the lists of discovered types and services stop changing.
            // This populates the list with all transitive dependencies of the input types/services to be fed into the
            // topological sort of verifyTypes() and verifyServices().
            int len;
            do {
                len = thriftTypes.size();
                for (int i = 0; i < len; i++) {
                    verifyStruct(thriftTypes.get(i), true);
                }
            } while (len != thriftTypes.size());
            do {
                len = thriftServices.size();
                for (int i = 0; i < len; i++) {
                    verifyService(thriftServices.get(i), true);
                }
            } while (len != thriftServices.size());
            recursive = false;
            usedIncludedTypes.clear();
            usedIncludedServices.clear();
            knownTypes = Sets.newHashSet(builtInKnownTypes);
            knownServices.clear();
        }
        // no short-circuit
        return verifyTypes() & verifyServices();
    }

    // verifies that all types are known (in thriftTypes or in include map)
    // and does a topological sort of thriftTypes in dependency order
    private boolean verifyTypes()
    {
        SuccessAndResult<ThriftType> output = topologicalSort(thriftTypes, new Predicate<ThriftType>()
        {
            @Override
            public boolean apply(@Nullable ThriftType t)
            {
                ThriftProtocolType proto = checkNotNull(t).getProtocolType();
                if (proto == ThriftProtocolType.ENUM || proto == ThriftProtocolType.STRUCT) {
                    return verifyStruct(t, true);
                } else {
                    Preconditions.checkState(false, "Top-level non-enum and non-struct?");
                    return false;   // silence compiler
                }
            }
        });
        if (output.success) {
            thriftTypes = output.result;
            return true;
        } else {
            for (ThriftType t: output.result) {
                // we know it's gonna fail, we just want the precise error message
                verifyStruct(t, false);
            }
            return false;
        }
    }

    private boolean verifyServices()
    {
        SuccessAndResult<ThriftServiceMetadata> output = topologicalSort(thriftServices, new Predicate<ThriftServiceMetadata>()
        {
            @Override
            public boolean apply(@Nullable ThriftServiceMetadata thriftServiceMetadata)
            {
                return verifyService(thriftServiceMetadata, true);
            }
        });
        if (output.success) {
            thriftServices = output.result;
            return true;
        } else {
            for (ThriftServiceMetadata s: output.result) {
                // we know it's gonna fail, we just want the precise error message
                verifyService(s, false);
            }
            return false;
        }
    }

    private class SuccessAndResult<T>
    {
        public boolean success;
        public ArrayList<T> result;
        SuccessAndResult(boolean success, ArrayList<T> result)
        {
            this.success = success;
            this.result = result;
        }
    }

    private <T> SuccessAndResult<T> topologicalSort(ArrayList<T> list, Predicate<T> isKnown)
    {
        ArrayList<T> remaining = list;
        ArrayList<T> newList = Lists.newArrayList();
        int prevSize = 0;
        while (prevSize != remaining.size()) {
            prevSize = remaining.size();
            ArrayList<T> bad = Lists.newArrayList();
            for (T t: remaining) {
                if (isKnown.apply(t)) {
                    newList.add(t);
                }
                else {
                    bad.add(t);
                }
            }
            remaining = bad;
        }
        if (prevSize == 0) {
            return new SuccessAndResult<>(true, newList);
        } else {
            return new SuccessAndResult<>(false, remaining);
        }
    }

    private boolean verifyService(ThriftServiceMetadata service, boolean quiet)
    {
        boolean ok = true;
        List<ThriftServiceMetadata> parents = service.getParentServices();

        Preconditions.checkState(
                parents.size() <= 1,
                "service " + service.getName() + " extends multiple services (thrift IDL does not support multiple inheritance for services)", service.getName());

        ThriftServiceMetadata parent = parents.size() == 0 ? null : parents.get(0);

        if (parent != null && !knownServices.contains(parent)) {
            if (includeMap.containsKey(parent)) {
                usedIncludedServices.add(parent);
            } else {
                ok = false;
                if (!quiet) {
                    LOG.error("Unknown parent service {} in {}",
                            parent.getName(),
                            service.getName());
                }
            }
        }

        for (Map.Entry<String, ThriftMethodMetadata> method : service.getDeclaredMethods().entrySet()) {
            for (ThriftFieldMetadata f : method.getValue().getParameters()) {
                if (!verifyField(f.getThriftType())) {
                    ok = false;
                    if (!quiet) {
                        LOG.error("Unknown argument type {} in {}.{}",
                                thriftTypeRenderer.toString(f.getThriftType()),
                                service.getName(),
                                method.getKey());
                    }
                }
            }

            for (ThriftType ex : method.getValue().getExceptions().values()) {
                if (!verifyField(ex)) {
                    ok = false;
                    if (!quiet) {
                        LOG.error("Unknown exception type {} in {}.{}",
                                thriftTypeRenderer.toString(ex),
                                service.getName(),
                                method.getKey());
                    }
                }
            }

            if (!method.getValue().getReturnType().equals(ThriftType.VOID) &&
                    !verifyField(method.getValue().getReturnType())) {
                ok = false;
                if (!quiet) {
                    LOG.error("Unknown return type {} in {}.{}",
                            thriftTypeRenderer.toString(method.getValue().getReturnType()),
                            service.getName(),
                            method.getKey());
                }
            }
        }

        knownServices.add(service);
        return ok;
    }

    private boolean verifyField(ThriftType t)
    {
        ThriftProtocolType proto = t.getProtocolType();
        if (proto == ThriftProtocolType.SET || proto == ThriftProtocolType.LIST) {
            return verifyField(t.getValueType());
        } else if (proto == ThriftProtocolType.MAP) {
            // no short-circuit
            return verifyField(t.getKeyType()) & verifyField(t.getValueType());
        } else {
            if (knownTypes.contains(t)) {
                return true;
            }

            if (includeMap.containsKey(t)) {
                usedIncludedTypes.add(t);
                return true;
            }

            if (recursive) {
                // recursive but type is unknown - add it to the list and recurse
                thriftTypes.add(t);
                return verifyStruct(t, true);
            }
            return false;
        }
    }

    private boolean verifyStruct(ThriftType t, boolean quiet)
    {
        if (t.getProtocolType() == ThriftProtocolType.ENUM) {
            knownTypes.add(t);
            return true;
        }
        ThriftStructMetadata metadata = t.getStructMetadata();
        boolean ok = true;
        for (ThriftFieldMetadata fieldMetadata: metadata.getFields(FieldKind.THRIFT_FIELD)) {
            boolean fieldOk = verifyField(fieldMetadata.getThriftType());
            if (!fieldOk) {
                ok = false;
                if (!quiet) {
                    LOG.error("Unknown type {} in {}.{}",
                              thriftTypeRenderer.toString(fieldMetadata.getThriftType()),
                              metadata.getStructName(),
                              fieldMetadata.getName());
                }
            }
        }

        if (ok) {
            knownTypes.add(t);
        }
        return ok;
    }

    private Class<?> load(String className)
    {
        className = getFullClassName(className);
        try {
			return Class.forName(className, false, getClassLoader());
        } catch (ClassNotFoundException e) {
            LOG.warn("Couldn't load class {}", className);
        }
        return null;
    }

    // returns ThriftType, ThriftServiceMetadata or null
    private Object convertToThrift(Class<?> cls)
    {
        Set<ThriftService> serviceAnnotations = ReflectionHelper.getEffectiveClassAnnotations(cls, ThriftService.class);
        if (!serviceAnnotations.isEmpty()) {
            // it's a service
        	// 使用自定义的ThriftServiceMetadata对象
            ThriftServiceMetadata serviceMetadata = new DecoratorThriftServiceMetadata(cls, catalog, 
            		MiscellaneousUtils.elementsOf(excludeMethods), 
            		MiscellaneousUtils.elementsOf(includeMethods),
            		sortByInclude);
            if (verbose) {
                LOG.info("Found thrift service: {}", cls.getSimpleName());
            }
            return serviceMetadata;
        } else {
            // it's a type (will throw if it's not)
            ThriftType thriftType = catalog.getThriftType(cls);
            if (verbose) {
                LOG.info("Found thrift type: {}", thriftTypeRenderer.toString(thriftType));
            }
            return thriftType;
        }
    }
    
    private void genThrift() throws IOException
    {
        ImmutableMap.Builder<ThriftType, String> typenameMap = ImmutableMap.builder();
        ImmutableMap.Builder<ThriftServiceMetadata, String> serviceMap = ImmutableMap.builder();
        ImmutableSet.Builder<String> includes = ImmutableSet.builder();
        for (ThriftType t: usedIncludedTypes) {
            String filename = includeMap.get(t);
            includes.add(filename);
            typenameMap.put(t, Files.getNameWithoutExtension(filename));
        }

        for (ThriftServiceMetadata s: usedIncludedServices) {
            String filename = includeMap.get(s);
            includes.add(filename);
            serviceMap.put(s, Files.getNameWithoutExtension(filename));
        }

        this.thriftTypeRenderer = new ThriftTypeRenderer(typenameMap.build());
        ThriftServiceMetadataRenderer serviceRenderer = new ThriftServiceMetadataRenderer(serviceMap.build());
        TemplateLoader tl = new TemplateLoader(ImmutableList.of("thrift/common.st"),
                ImmutableMap.of(
                        ThriftType.class, thriftTypeRenderer,
                        ThriftServiceMetadata.class, serviceRenderer,
                        Requiredness.class, new FieldRequirednessRenderer()));
        ThriftContext ctx = new ThriftContext(packageName, ImmutableList.copyOf(includes.build()), thriftTypes, thriftServices, namespaceMap);
        ST template = tl.load("thriftfile");
        template.add("context", ctx);
        template.write(new AutoIndentWriter(outputStreamWriter));
        outputStreamWriter.flush();
    }
    
    private void genErpc() throws IOException
    {
        DecoratorThriftFieldMetadata.requirednessFilter = new CodegenRequirednessFilter();
        DecoratorThriftFieldMetadata.sizeLimitAnnotationGetter = new CodegenErpcSizeLimitGetter();
        DecoratorThriftFieldMetadata.typePrefixGetter = new ErpcTypePrefixGetter();
        DecoratorThriftFieldMetadata.preAllocFilter = CodegenPreAllocFilter.PREALLOC_FILTER;
        DecoratorThriftFieldMetadata.documentAppender = new CodegenExtDocument();
        ImmutableMap.Builder<ThriftType, String> typenameMap = ImmutableMap.builder();
        ImmutableMap.Builder<ThriftServiceMetadata, String> serviceMap = ImmutableMap.builder();
        ImmutableSet.Builder<String> includes = ImmutableSet.builder();
        for (ThriftType t: usedIncludedTypes) {
            String filename = includeMap.get(t);
            includes.add(filename);
            typenameMap.put(t, Files.getNameWithoutExtension(filename));
        }

        for (ThriftServiceMetadata s: usedIncludedServices) {
            String filename = includeMap.get(s);
            includes.add(filename);
            serviceMap.put(s, Files.getNameWithoutExtension(filename));
        }

        this.thriftTypeRenderer = new ThriftTypeRenderer(typenameMap.build());
        ThriftServiceMetadataRenderer serviceRenderer = new ThriftServiceMetadataRenderer(serviceMap.build());
        ErpcTypeRenderer erpcTypeRenderer = new ErpcTypeRenderer();
        //STGroup.verbose=true;
        TemplateLoader tl = new TemplateLoader(ImmutableList.of("erpc/common.st"),
                ImmutableMap.of(
                		ThriftType.class, erpcTypeRenderer,
                        ErpcType.class, erpcTypeRenderer,
                        Enum.class,new EnumErpcRender(),
                        DecoratorThriftFieldMetadata.class,new ErpcThriftFieldMetadataRenderer(),
                        ThriftServiceMetadata.class, serviceRenderer));
        ThriftType erpcProxyReturnType = null;
        if(erpcProxy){
        	DecoratorThriftEnumMetadata.beforeExtensiveEnumItems = createBeforeExtensiveEnumItem();
        	erpcProxyReturnType = catalog.getThriftType(ErpcProxyReturnCode.class);
        	// 添加到列表头部
        	if(thriftTypes.isEmpty()){
        		thriftTypes.add(erpcProxyReturnType);
        	}else{
        		thriftTypes.add(0,erpcProxyReturnType);
        	}        	
        }
		// 过滤所有异常类型
		Iterable<ThriftType> filtered = Iterables.filter(thriftTypes, new Predicate<ThriftType>() {

			@Override
			public boolean apply(ThriftType input) {
				return ! Exception.class.isAssignableFrom(TypeToken.of(input.getJavaType()).getRawType());
			}
		});
		ArrayList<ThriftType> typesWithoutException = Lists.newArrayList(filtered);
        ThriftContextErpc ctx = new ThriftContextErpc(packageName, ImmutableList.copyOf(includes.build()), typesWithoutException, thriftServices, namespaceMap, 
        			programName, portPrefix, defaultMaxLength, errmsgMaxLength, erpcProxy, erpcProxyReturnType);
        
        DecoratorThriftEnumMetadata.enumNameTransformer = ErpcNameTransformer.erpcTypeNameTransformer;
        DecoratorThriftStructMetadata.structNameTransformer = ErpcNameTransformer.erpcTypeNameTransformer;
        DecoratorThriftFieldMetadata.fieldNameTransformer =  ErpcNameTransformer.erpcFieldNameTransformer;
        DecoratorThriftFieldMetadata.parameterNameTransformer = ErpcNameTransformer.erpcParemeterNameTransformer;
        ST template = tl.load("erpcfile");
        template.add("context", ctx);
        template.write(new AutoIndentWriter(outputStreamWriter));
        outputStreamWriter.flush();
    }
    private void gen() throws IOException
    {
    	if(generateErpcIDL){
    		genErpc();	
    	}else{
    		genThrift();
    	}
    }

	private ClassLoader getClassLoader() {
		if (null == classLoader) {
			synchronized (this) {
				if (null == classLoader) {
					classLoader = ClassLoaderUtils.buildClassLoader(JavadocReader.getClasspath(), 
							parentClassLoader, false);
				}
			}
		}
		return classLoader;
	}
    /**
     * 定义IDL中要排除的方法名列表(逗号或分号分隔)
	 * @param excludeMethods 要设置的 excludeMethods
	 * @return 当前对象
	 */
    public Swift2ThriftGenerator setExcludeMethods(String excludeMethods){
    	if(excludeMethods != null){
    		this.excludeMethods = excludeMethods;	
    	}
    	return this;
    }

	/**
	 * @param includeMethods 要设置的 includeMethods
	 */
    public Swift2ThriftGenerator setIncludeMethods(String includeMethods) {
    	if(includeMethods != null){
    		this.includeMethods = includeMethods;
    	}
		return this;
	}

    public Swift2ThriftGenerator setSortByInclude(boolean sortByInclude) {
		this.sortByInclude = sortByInclude;
		return this;
	}

	/**
	 * 指定是否生成ePRC IDL 文件(默认为false则生成thrift IDL)
	 * @param generateErpcIDL 要设置的 generateErpcIDL
	 * @return 当前对象
	 */
    public Swift2ThriftGenerator setGenerateErpcIDL(boolean generateErpcIDL) {
		this.generateErpcIDL = generateErpcIDL;
		return this;
	}

	/**
	 * 定义ePRC IDL 项目名称('program')
	 * @param programName 要设置的 programName
	 * @return 当前对象
	 */
	public Swift2ThriftGenerator setProgramName(String programName) {
		this.programName = programName;
		return this;
	}

	/**
	 * 定义ePRC IDL 接口方法名前缀,默认为空
	 * @param portPrefix 要设置的 portPrefix
	 * @return 当前对象
	 */
	public Swift2ThriftGenerator setPortPrefix(String portPrefix) {
		this.portPrefix = portPrefix;
		return this;
	}

	/**
	 * 定义源码路径用于通过javadoc读取代码注释
	 * @param sourcepath 要设置的 sourcepath
	 * @return 当前对象
	 */
	public Swift2ThriftGenerator setSourcepath(String sourcepath) {
		JavadocReader.setSourcepath(sourcepath);

		return this;
	}

	/**
	 * 定义classpath用于javadoc执行时查找引用的类
	 * @param classpath 要设置的 classpath
	 * @return 当前对象
	 */
	public Swift2ThriftGenerator setClasspath(String classpath) {
		JavadocReader.setClasspath(classpath);
		return this;
	}

	/**
	 * 定义父级{@link ClassLoader}
	 * @param parentClassLoader 要设置的 parentClassLoader
	 * @return 当前对象
	 * @since 1.25
	 */
	public Swift2ThriftGenerator setParentClassLoader(ClassLoader parentClassLoader) {
		this.parentClassLoader = parentClassLoader;
		return this;
	}

	
	/**
	 * 当没有定义找到{@link com.facebook.swift.codec.ThriftDocumentation}定义的文档数据时,
	 * 是否使用javadoc从源码读取的注释作为文档数据
	 * @param javadocEnable 要设置的 javadocEnable
	 * @return 当前对象
	 */
	public Swift2ThriftGenerator setJavadocEnable(boolean javadocEnable) {
		javadocCommentProviderFactory = javadocEnable ? new ClassCommentProviderFactoryImpl() : null;
		return this;
	}

	/**
	 * 定义ePRC IDL '@max_length'注释的默认值
	 * @param defaultMaxLength 要设置的 defaultMaxLength
	 * @return 当前对象
	 */
	public Swift2ThriftGenerator setDefaultMaxLength(int defaultMaxLength) {
		this.defaultMaxLength = defaultMaxLength;
		return this;
	}
	/**
	 * 定义ePRC IDL 方法调用返回值错误信息字符串的最大长度( '@max_length'注释的值)
	 * @param errmsgMaxLength 要设置的 errmsgMaxLength
	 * @return 当前对象
	 */
	public Swift2ThriftGenerator setErrmsgMaxLength(int errmsgMaxLength) {
		this.errmsgMaxLength = errmsgMaxLength;
		return this;
	}
	/**
	 * 是否生成eRPC代理服务,默认false
	 * @param erpcProxy 要设置的 erpcProxy
	 * @return 当前对象
	 */
	public Swift2ThriftGenerator setErpcProxy(boolean erpcProxy) {
		this.erpcProxy = erpcProxy;
		return this;
	}

	/**
	 * @param excludeFields 要设置的 excludeFields
	 * @return 当前对象
	 */
	public Swift2ThriftGenerator setExcludeFields(Map<String, String> excludeFields) {
		HashMap<String, String> m = Maps.newHashMap();
		if(generateErpcIDL){
			m.putAll(defaultExcludeFields);
		}
		if(excludeFields != null){
			m.putAll(excludeFields);
		}
		Map<Class<?>, List<String>> excludeFieldsOfClass = Maps.newHashMap();
		for(Entry<String, String> entry:m.entrySet()){
			excludeFieldsOfClass.put(load(entry.getKey()), MiscellaneousUtils.elementsOf(entry.getValue()));
		}
        DecoratorThriftStructMetadata.fieldNameFilters = new FieldNameFilters(excludeFieldsOfClass);
		return this;
	}

	private ImmutableMap<Class<? extends Enum<?>>, List<ExtensiveEnumItem>> createBeforeExtensiveEnumItem(){
		ArrayList<ExtensiveEnumItem> items = Lists.newArrayList();
		for(ThriftType type:thriftTypes){
			Class<?> javaType = (Class<?>) type.getJavaType();
			if(javaType instanceof Class<?> && Exception.class.isAssignableFrom(javaType)){
				 ImmutableList<String> comment = null;
					if (withValidFactory()) {
						comment = ImmutableList.copyOf(providerOf(javaType).commentOfClass());
					}
				items.add(new ExtensiveEnumItem(javaType.getSimpleName(),null,comment));
			}
		}
		return ImmutableMap.<Class<? extends Enum<?>>, List<ExtensiveEnumItem>>of(ErpcProxyReturnCode.class,items);
	}
}
